Skip to content

feat(apps): emit typed error envelopes across the apps domain#1288

Open
evandance wants to merge 1 commit into
mainfrom
feat/errs-migrate-apps
Open

feat(apps): emit typed error envelopes across the apps domain#1288
evandance wants to merge 1 commit into
mainfrom
feat/errs-migrate-apps

Conversation

@evandance

@evandance evandance commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator

Summary

Apps errors previously left several command-facing paths as legacy output.Err* / output.Errorf envelopes or untyped helper errors, so callers had to recover validation, API, and file failures from prose. This PR makes the apps domain's own error producers — flag validation, local HTML publish file handling, SDK/API boundaries, and Miaoda HTML publish business errors — emit typed errs.* errors with stable type, subtype, param / params, hint, code, log_id, and retryable metadata where available.

What to focus on (reviewer guide)

  1. Consumer-visible error envelope changes: apps validation now carries validation/invalid_argument plus param; missing index.html is validation/failed_precondition; local pack/read failures carry typed validation or internal/file_io classification.
  2. API-boundary migration: standard apps JSON calls use runtime.CallAPITyped; multipart HTML publish keeps raw DoAPI because it posts multipart form data, but classifies responses via runtime.ClassifyAPIResponse and wraps SDK-boundary failures with client.WrapDoAPIError.
  3. HTML publish code-specific recovery: business codes 90001 / 90002 are scoped to this endpoint, so both their classification (90002api/not_found) and their recovery hints live in the apps domain instead of the global API code table — the global table stays reserved for service-namespaced codes. Enrichment never overrides a stronger upstream classification and preserves code / log_id.
  4. Response-shape tightening: an HTML publish success response that omits the published app url now fails as internal/invalid_response instead of returning an empty url.
  5. Anti-backslide lock: .golangci.yml and lint/errscontract opt shortcuts/apps/ into typed-only, no-bare-wrap, no-legacy-helper, legacy-envelope, and legacy-runtime-helper guards.
  6. Scope: apps currently has no batch command or multi-status output path, so this migration does not add an OutPartialFailure flow.

Changes

  • Replace apps-domain legacy validation, file I/O, and final error producers with typed errs.* builders and apps-local helper functions.
  • Switch standard apps API calls from runtime.CallAPI to runtime.CallAPITyped.
  • Keep HTML publish multipart upload on raw DoAPI, while routing response classification through runtime.ClassifyAPIResponse and SDK boundary errors through client.WrapDoAPIError.
  • Classify HTML publish endpoint business codes locally (90002api/not_found) and keep their recovery hints local, since these codes are endpoint-scoped rather than service-global; hints are normalized to English.
  • Reject an HTML publish success response that lacks the published app url as internal/invalid_response.
  • Add apps to golangci and errscontract migrated-path guards to prevent legacy error regressions.
  • Update apps tests to assert errs.ProblemOf metadata instead of legacy output.ExitError details, and add helper-level tests for path, file I/O, API boundary lifting, endpoint-local code classification, and hint enrichment (including subtype / log_id preservation).
  • Isolate apps runtime tests with a temporary LARKSUITE_CLI_CONFIG_DIR so they do not read or write user config state.

Test Plan

  • gofmt -l .
  • git diff --check
  • go mod tidy produced no go.mod / go.sum diff
  • go vet ./...
  • go test ./shortcuts/apps ./internal/errclass ./internal/client
  • go test ./errscontract from the lint module
  • go run -C lint . ..
  • golangci-lint v2.1.6 run --new-from-rev=origin/main — 0 issues
  • make unit-test
  • Manual dry-run: lark-cli apps +create --name Demo --app-type HTML --dry-run --as user
  • Manual dry-run: lark-cli apps +html-publish --app-id app_x --path <site> --dry-run --as user

Output changes for consumers

  • Apps command errors now expose typed type / subtype plus stable fields such as param, hint, code, log_id, and retryable where the underlying failure provides them.
  • Local HTML publish input failures are classified as validation or file I/O conditions instead of generic prose-only errors.
  • Known HTML publish API failures keep their upstream code / log_id and gain command-specific recovery hints; code 90002 is classified api/not_found.
  • An HTML publish success response without the published app url fails as internal/invalid_response instead of printing an empty url.

Out of scope / deferred

  • Shared auth, scope, credential, and transport failures remain owned by the shared runtime/client layers; apps preserves typed errors from those layers instead of reclassifying them locally.
  • Apps has no current batch or partial-success command, so there is no per-item structured failure shape to migrate in this PR.

Related Issues

N/A

Summary by CodeRabbit

  • Improvements

    • Standardized and clarified error reporting across Apps commands (validation, precondition, API, file I/O), with better hints and recovery guidance.
    • Consistent CLI parameter validation for create/update/publish/access-scope/list; preserved existing success output formats.
    • HTML publish: more robust API response handling and clearer published-URL error messages; failure hints now in English.
  • Tests

    • Expanded tests to assert structured error classifications, recovery hints, and HTML publish error behaviors.

@coderabbitai

coderabbitai Bot commented Jun 5, 2026

Copy link
Copy Markdown

Too many files changed? Review this PR in Change Stack to see how the pieces fit before you dive in.

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR migrates the shortcuts/apps package from legacy internal/output error handling to typed errs.Problem errors, updates lint rules and error infrastructure, switches API calls to typed responses, and standardizes error assertions in tests across all apps commands and features.

Changes

Apps Domain Typed Error Migration

Layer / File(s) Summary
Lint configuration and error infrastructure
.golangci.yml, lint/errscontract/rule_no_legacy_common_helper_call.go, lint/errscontract/rule_no_legacy_envelope_literal.go, shortcuts/apps/apps_errors.go
forbidigo rule exclusions and lint contract paths extended to include shortcuts/apps/. New error constructors for validation, precondition, file-IO, and API-boundary failures with cause-chain support.
Simple commands: validation and typed API calls
shortcuts/apps/apps_access_scope_get.go, shortcuts/apps/apps_create.go, shortcuts/apps/apps_list.go, shortcuts/apps/apps_update.go, shortcuts/apps/apps_create_test.go
Validation errors migrated from output.ErrValidation to appsValidationParamError. Internal/output imports removed. API calls switched from CallAPI to CallAPITyped. Test helpers added to assert *errs.Problem category.
Access-scope-set: comprehensive flag validation
shortcuts/apps/apps_access_scope_set.go
Validation refactored to return appsValidationParamError for parameter failures, JSON unmarshal errors wrapped via WithCause, and per-flag invalid markers via WithParams. API call switched to CallAPITyped.
HTML publish validation and error handling
shortcuts/apps/apps_html_publish.go
Required parameter validation, sensitive credential blocking, index.html precondition, and size-limit checks refactored to use appsValidationParamError and appsFailedPreconditionParamError with hints. Publisher/API errors wrapped via client.WrapDoAPIError.
HTML publish client response handling
shortcuts/apps/html_publish_client.go
ClassifyAPIResponse replaces JSON envelope parsing. Missing/empty url returns internal error. enrichHTMLPublishAPIError wraps both untyped and typed API failures and updates failure hints to English.
HTML publish tarball and candidate-walker errors
shortcuts/apps/html_publish_tarball.go, shortcuts/apps/walk_html_publish_candidates.go
Tarball packing and walk errors switched from fmt.Errorf/errors.New to appsValidationParamError, appsFileIOError, and appsInputPathEntryError with preserved context.
Test updates: error assertion standardization
shortcuts/apps/apps_errors_test.go, shortcuts/apps/apps_html_publish_test.go, shortcuts/apps/html_publish_client_test.go
New tests for apps error classification and enrichment; HTML publish tests standardized on requireAppsValidationProblem/requireAppsAPIProblem and add app-not-found classification test.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • larksuite/cli#1242: Extends lint migrated-path logic for shortcuts domains similar to this PR's addition of shortcuts/apps/.
  • larksuite/cli#1072: Previously modified apps_html_publish.go credential scanning; this PR refactors validation/error handling in the same file.
  • larksuite/cli#1002: Introduced or modified apps commands that this PR migrates to typed errors and typed API calls.

Suggested labels

domain/ccm, size/L, feature

Suggested reviewers

  • liangshuo-1
  • liuxinyanglxy
  • kongenpei

"🐰 I hopped through code and sorted the fray,
apps errors now speak in Problem way.
Legacy output set aside,
hints and causes kept with pride,
tests assert the typed errors today."

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.93% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: migrating the apps domain to emit typed error envelopes, which matches the core objective throughout the changeset.
Description check ✅ Passed The PR description comprehensively covers all required template sections: clear summary, detailed changes list, thorough test plan with checkmarks, related issues noted, and additional context for reviewers.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/errs-migrate-apps

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added the size/L Large or sensitive change across domains or core paths label Jun 5, 2026
@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown

🚀 PR Preview Install Guide

🧰 CLI update

npm i -g https://pkg.pr.new/larksuite/cli/@larksuite/cli@e76456c923dd4c1e82f1370e37d1f3b57da387b5

🧩 Skill update

npx skills add larksuite/cli#feat/errs-migrate-apps -y -g

@codecov

codecov Bot commented Jun 5, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 72.56637% with 31 lines in your changes missing coverage. Please review.
✅ Project coverage is 71.58%. Comparing base (03ea6e7) to head (e76456c).

Files with missing lines Patch % Lines
shortcuts/apps/apps_access_scope_set.go 60.86% 9 Missing ⚠️
shortcuts/apps/apps_errors.go 77.14% 4 Missing and 4 partials ⚠️
shortcuts/apps/walk_html_publish_candidates.go 20.00% 4 Missing ⚠️
shortcuts/apps/apps_html_publish.go 83.33% 3 Missing ⚠️
shortcuts/apps/apps_create.go 50.00% 2 Missing ⚠️
shortcuts/apps/html_publish_tarball.go 71.42% 2 Missing ⚠️
shortcuts/apps/apps_access_scope_get.go 50.00% 1 Missing ⚠️
shortcuts/apps/apps_update.go 85.71% 1 Missing ⚠️
shortcuts/apps/html_publish_client.go 90.90% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1288   +/-   ##
=======================================
  Coverage   71.58%   71.58%           
=======================================
  Files         689      690    +1     
  Lines       65521    65558   +37     
=======================================
+ Hits        46901    46932   +31     
- Misses      14972    14975    +3     
- Partials     3648     3651    +3     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
shortcuts/apps/html_publish_client_test.go (1)

21-31: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add config-dir isolation in the test runtime helper.

newAppsClientRuntime uses cmdutil.TestFactory but does not isolate config state. This can leak state across tests when config-backed paths are touched.

💡 Suggested fix
 func newAppsClientRuntime(t *testing.T) (*common.RuntimeContext, *httpmock.Registry) {
 	t.Helper()
+	t.Setenv("LARKSUITE_CLI_CONFIG_DIR", t.TempDir())
 	cfg := &core.CliConfig{
 		AppID:      "test-app-" + strings.ToLower(t.Name()),
 		AppSecret:  "test-secret",
 		Brand:      core.BrandFeishu,
 		UserOpenId: "ou_test",
 	}

As per coding guidelines: **/*_test.go must Use t.Setenv("LARKSUITE_CLI_CONFIG_DIR", t.TempDir()) to isolate config state in tests.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@shortcuts/apps/html_publish_client_test.go` around lines 21 - 31, The test
helper newAppsClientRuntime should isolate config state: before calling
cmdutil.TestFactory set the environment var LARKSUITE_CLI_CONFIG_DIR to a temp
dir via t.Setenv("LARKSUITE_CLI_CONFIG_DIR", t.TempDir()), so tests don't share
config-backed paths; update newAppsClientRuntime to call t.Setenv(...) as the
first action in the function (reference newAppsClientRuntime and the call site
cmdutil.TestFactory).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@shortcuts/apps/html_publish_client_test.go`:
- Around line 21-31: The test helper newAppsClientRuntime should isolate config
state: before calling cmdutil.TestFactory set the environment var
LARKSUITE_CLI_CONFIG_DIR to a temp dir via t.Setenv("LARKSUITE_CLI_CONFIG_DIR",
t.TempDir()), so tests don't share config-backed paths; update
newAppsClientRuntime to call t.Setenv(...) as the first action in the function
(reference newAppsClientRuntime and the call site cmdutil.TestFactory).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: cad262b6-f9b7-409c-93ee-75177089ac7c

📥 Commits

Reviewing files that changed from the base of the PR and between f3949f0 and deb12eb.

📒 Files selected for processing (17)
  • .golangci.yml
  • internal/errclass/codemeta_apps.go
  • lint/errscontract/rule_no_legacy_common_helper_call.go
  • lint/errscontract/rule_no_legacy_envelope_literal.go
  • shortcuts/apps/apps_access_scope_get.go
  • shortcuts/apps/apps_access_scope_set.go
  • shortcuts/apps/apps_create.go
  • shortcuts/apps/apps_create_test.go
  • shortcuts/apps/apps_errors.go
  • shortcuts/apps/apps_html_publish.go
  • shortcuts/apps/apps_html_publish_test.go
  • shortcuts/apps/apps_list.go
  • shortcuts/apps/apps_update.go
  • shortcuts/apps/html_publish_client.go
  • shortcuts/apps/html_publish_client_test.go
  • shortcuts/apps/html_publish_tarball.go
  • shortcuts/apps/walk_html_publish_candidates.go

@evandance evandance force-pushed the feat/errs-migrate-apps branch from deb12eb to 8920914 Compare June 6, 2026 03:16
@evandance evandance changed the title refactor(apps): migrate errors to typed taxonomy feat(apps): emit typed error envelopes across the apps domain Jun 6, 2026
@github-actions github-actions Bot added size/M Single-domain feat or fix with limited business impact and removed size/L Large or sensitive change across domains or core paths labels Jun 6, 2026
@evandance evandance force-pushed the feat/errs-migrate-apps branch 5 times, most recently from bf3234d to 166ca41 Compare June 9, 2026 03:47
@evandance evandance force-pushed the feat/errs-migrate-apps branch from 166ca41 to e76456c Compare June 9, 2026 04:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/M Single-domain feat or fix with limited business impact

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant